// Qt on Metro plugin
// Copyright (c) Andrew Knight
// This software is licensed under the MIT: http://www.opensource.org/licenses/MIT
// This software uses Qt (http://qt.nokia.com)

#include "metroapplication.h"
#include <QtCore/QtPlugin>
#include <QtCore/QEvent>
#include <QtGui/QApplication>
#include <QtGui/QMouseEvent>
#include <QtGui/QGraphicsSceneMouseEvent>
#include <QtGui/QGraphicsRectItem>
#include <QtGui/QStyleOptionGraphicsItem>
#include <QtDeclarative/QDeclarativeComponent>
#include <QtDeclarative/QDeclarativeItem>
#include <QDebug>

MetroApplication::MetroApplication() :
    m_engine(this),
    m_context(&m_engine, this),
    m_rootItem(0),
    m_layoutState(Fullscreen)
{
    m_scene.setItemIndexMethod(QGraphicsScene::NoIndex);
    m_scene.setStickyFocus(false);
    //m_rootItem->setAcceptHoverEvents(true);
    //m_scene.setBackgroundBrush(QBrush(Qt::blue));
    //QGraphicsRectItem* item = m_scene.addRect(500, 500, 100, 100, QPen(), QBrush(Qt::red));
    //item->setFlag(QGraphicsItem::ItemIsMovable);
    //item->setFlag(QGraphicsItem::ItemIsSelectable);
}

void MetroApplication::start()
{
    QDeclarativeComponent qml(&m_engine, QUrl("qrc:/main.qml"), this);
    qDebug() << qml.errorString();
    m_rootItem = qobject_cast<QDeclarativeItem*>(qml.create(&m_context));
    changeLayout(m_layoutState);
    m_scene.addItem(m_rootItem);
}

void MetroApplication::resize(const QSize size)
{
    if(size == m_image.size())
        return;
    m_image = QImage(size, QImage::Format_RGB32);
    m_scene.setSceneRect(0, 0, size.width(), size.height());
    if(m_rootItem) {
        m_rootItem->setPos(0, 0);
        m_rootItem->setHeight(size.height());
        changeLayout(m_layoutState);
    }
}

void MetroApplication::changeLayout(const LayoutState layout)
{
    m_layoutState = layout;
    if(m_rootItem) {
        switch(layout) {
        case Fullscreen:
            m_rootItem->setWidth(m_scene.width());
            break;
        case Filled:
            m_rootItem->setWidth(m_scene.width() - 342);
            break;
        case Snapped:
            m_rootItem->setWidth(320);
            break;
        }
    }
}

void MetroApplication::render()
{
    QPainter painter(&m_image);
    if(m_image.size().isValid())
        m_scene.render(&painter);
}

bool MetroApplication::event(QEvent *ev)
{
    QMouseEvent* e = reinterpret_cast<QMouseEvent*>(ev);
    QEvent::Type type;
    switch(ev->type()) {
    case QEvent::MouseButtonPress:
        type = QEvent::GraphicsSceneMousePress;
        m_lastMouseDownButton = e->button();
        m_lastMouseDownPos = e->pos();
        break;
    case QEvent::MouseMove:
        type = QEvent::GraphicsSceneMouseMove;
        break;
    case QEvent::MouseButtonRelease:
        type = QEvent::GraphicsSceneMouseRelease;
        break;
    case QEvent::Wheel: {
        QWheelEvent* w = reinterpret_cast<QWheelEvent*>(ev);
        QGraphicsSceneWheelEvent mouseEvent(QEvent::GraphicsSceneWheel);
        mouseEvent.setPos(w->pos());
        mouseEvent.setDelta(w->delta());
        mouseEvent.setOrientation(Qt::Vertical);
        QApplication::sendEvent(&m_scene, &mouseEvent);
    }   return true;
    default:
        return QObject::event(ev);
    }

    QGraphicsSceneMouseEvent mouseEvent(type);

    mouseEvent.setButtonDownScenePos(m_lastMouseDownButton, m_lastMouseDownPos);
    mouseEvent.setScenePos(e->pos());
    mouseEvent.setLastScenePos(m_lastMousePos);
    mouseEvent.setButtons(e->buttons());
    mouseEvent.setButton(e->button());
    mouseEvent.setModifiers(e->modifiers());
    mouseEvent.setAccepted(false);

    //irrelevant?
    /*mouseEvent.setWidget(0);
    mouseEvent.setButtonDownScreenPos(m_lastMouseDownButton, m_lastMouseDownPos);
    mouseEvent.setScreenPos(e->pos());
    mouseEvent.setLastScreenPos(m_lastMousePos);*/

    QApplication::sendEvent(&m_scene, &mouseEvent);
    e->setAccepted(mouseEvent.isAccepted());

    m_lastMousePos = e->pos();

    return true;
}

const QImage MetroApplication::image()
{
    return QImage(m_image);
}

Q_EXPORT_PLUGIN2(metro, MetroApplication)
